import threading, thread
import gobject, gtk
import Sysaccess
import Exceptions
gtk.gdk.threads_init()

class PygtkThreads(gobject.GObject):
    
    __gsignals__ = {
            # set signal is emit when a share is set
            # callback has to look like : def callback(threads, thread_name)
            'start' : (gobject.SIGNAL_DETAILED, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
            # set signal is emit when a share is set
            # callback has to look like : def callback(threads, thread_name)
            'end' : (gobject.SIGNAL_DETAILED, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
         }
    
    def __init__(self, controller ):
        gobject.GObject.__init__(self)
        
        self.controller = controller
        self.config = self.controller.config
        
        self.launchers = {'LATENCY'      : self.latency_thread_launcher,
                         'NETWORK STATE' : self.network_state_thread_launcher,
                         'MTAB'          : self.mtab_thread_launcher,
                         'AUTOMOUNT'     : self.automount_thread_launcher,
                         'NETWORK INFO'  : self.network_info_thread_launcher,
                         'MOUNT'         : self.mount_thread_launcher,
                         'UNMOUNT'       : self.unmount_thread_lancher,
        }
        
        self.time = 1
        self.started = {}
        self.started_lock = False
        self.launch_timer()
    
    def __wait__(self):
        print "waiting"
        while self.started_lock: 
            pass
        print "stop waiting"
    
    def launch_timer(self):
        self.stop = False
        PygtkThread(self,'TIMER',self.timer).start()
    
    def timer(self):
        if not self.stop:
            t = threading.Timer(1.0, self.timer)
            t.start()
            self.time += 1
            self.started_lock = True   
            for thread,offset in self.started.iteritems():
                if offset:
                    if offset + self.config.user['TIMERS'][thread] <= self.time:
                        self.launch(thread)
            self.started_lock = False
        
    def launch(self,thread,*args):
        if thread in self.started:
            if self.started[thread]:
                self.started[thread] = self.time
        self.launchers[thread](args)
    
    def start_thread(self,thread):
        if self.started_lock:
            self.__wait__()
        if not thread in self.started:
            self.started[thread] = self.time
            self.launch(thread)
    
    def stop_thread(self,thread):
        if self.started_lock:
            self.__wait__()
        if thread in self.started:
            del self.started[thread]
    
    # Network state thread
    def network_state_thread_launcher(self,args):
        PygtkThread(self,'NETWORK STATE',self.network_state_thread_action).start()
        return True
    
    def network_state_thread_action(self):
        interface,gateway = Sysaccess.get_default_route()
        self.config.network['INTERFACE'] = interface
        self.config.network['GATEWAY'] = gateway
        if interface:
                self.config.network['STATE'] = True
        else:
                self.config.network['STATE'] = False
    
    # Network info Thread
    def network_info_thread_launcher(self,args):
        PygtkThread(self,'NETWORK INFO',self.network_info_thread_action).start()
        info = Sysaccess.get_interface_info(self.config.network['INTERFACE'])
        print info 
        if info:
            ip,mask,bcast = info 
            self.config.network['LOCAL ADDR'] = ip
            self.config.network['NETMASK'] = mask
        return True
    
    def network_info_thread_action(self):
        ip = Sysaccess.get_public_addr()
        if ip:
            self.config.network['PUBLIC ADDR'] = ip
        else:
            self.config.network['PUBLIC ADDR'] = None
        
    # Latency thread
    def latency_thread_launcher(self,args):
        share = None
        join = None
        if len(args) > 0:
            share = args[0]
        if len(args) > 1:
            join = args[1]
        
        if share:
            if join:
                PygtkThread(self,'LATENCY',self.latency_thread_action,self.latency_thread_callback,share).start(share).join()
            else:
                PygtkThread(self,'LATENCY',self.latency_thread_action,self.latency_thread_callback,share).start(share)
        else:
            for share_id,share in self.controller.shares:
                if share.location.id == 0 or share.location == self.config.network['CURRENT LOCATION'] or share.mounted == True :
                    PygtkThread(self,'LATENCY',self.latency_thread_action,self.latency_thread_callback,share).start(share)
        return True
    
    def latency_thread_action(self,share):
        share.tmp = None
        share.tmp = Sysaccess.get_host_latency(share.server,share.port)
            
    def latency_thread_callback(self,args):
        share = args[0]
        self.controller.shares.set_latency(share,share.tmp)

    # mtab thread
    def mtab_thread_launcher(self,args):
        PygtkThread(self,'MTAB',self.mtab_thread_action).start()
        return True
    
    def mtab_thread_action(self):
        self.controller.mtab.refresh()
        
    def mount_thread_launcher(self,args):
        share = args[0]
        if not share.locked:
            PygtkThread(self,'MOUNT',self.mount_thread_action,self.mount_thread_callback,share).start(share)
    
    def mount_thread_action(self,share):
        print 'lock ' + str(share)
        share.locked = True
        
        try:
            if share.protocol == 'SSH':
                Sysaccess.check_host_pub_key(share)
            Sysaccess.mount(share)
        except Exceptions.UnknownHostPubKey,e:
            share.lock_automount = True
            import Dialog
            title = 'Unknonwn Host Key'
            msg = 'The authenticity of host %s can\'t be established.\nAre you sure you want to continue connecting ?'% share.server
            Dialog.ThreadSafeDialog(self.controller,title,msg,self.add_ssh_pub_key,share,e.key)
        except Exception,e:
            print e.__str__()
            if share.automount:
                share.lock_automount = True
            self.controller.trayicon.notif(e.__str__())
        
        finally:
            print 'unlock' + str(share)
            share.locked = False
            
    def mount_thread_callback(self,share):
        share = share[0]
        self.controller.mtab.refresh()
        if share.mounted:
            msg = share.name + " is now mounted\nOn " +share.mount_point
            self.controller.trayicon.notif(msg)
    
    def unmount_thread_lancher(self,args):
        share = args[0]
        if share:
            if share.mounted and not share.locked:
                PygtkThread(self,'UNMOUNT',self.unmount_thread_action,self.unmount_thread_callback,share).start(share)
        else:
            for share_id,share in self.controller.shares:
                if share.mounted and not share.locked:
                    self.launch('UNMOUNT',share)

    def unmount_thread_action(self,share):
        if share.mounted:
            Sysaccess.unmount(share)
    
    def unmount_thread_callback(self,share):
        share = share[0]
        self.controller.mtab.refresh()
        if share:
            if not share.mounted:
                msg = share.name + " has been successfully unmounted"
                self.controller.trayicon.notif(msg)
        else:
            if not len(self.controller.mtab.mounted_shares):
                msg = "All remote shares have been successfully unmounted"
                self.controller.trayicon.notif(msg)
                
    def add_ssh_pub_key(self,args):
        share = args[0]
        key = args[1]
        try:
            Sysaccess.add_host_pub_key(key,self.config.path['SSH ROOT HOST KEY FILE'])
            self.launch('MOUNT',share)
            share.lock_automount = False
        except:
            #need notification?
            pass
    
    def automount_thread_launcher(self,args):
        PygtkThread(self,'AUTOMOUNT',self.automount_thread_action,self.automount_thread_callback).start()
        return True
    
    def automount_thread_action(self):
        if self.config.network['STATE']:
            self.controller.mtab.refresh()
            for id,share in self.controller.shares:
                if (share.automount or share.remount) and not share.lock_automount and not share.mounted and isinstance(share.latency,int):
                    if share.remount:
                        share.remount = False
                    self.launch('MOUNT',share)
                elif not isinstance(share.latency,int) and share.mounted:
                    if not share.automount:
                        share.remount = True
                    self.launch('UNMOUNT',share)
    
    def automount_thread_callback(self):
        self.controller.mtab.refresh()

class PygtkThread(object):
    def __init__(self,threads,name, thread_action, thread_callback=None,*thread_callback_args):
        self.threads = threads
        self.name = name
        self.thread_action = thread_action
        self.thread_callback = thread_callback
        self.thread_callback_args = thread_callback_args
       
    def _start(self,*args):
        self.threads.emit('start',self.name)
        self.thread_action(*args)
        if self.thread_callback:
            if len(self.thread_callback_args) > 0:
                gobject.idle_add(self.thread_callback,self.thread_callback_args)
            else:
                gobject.idle_add(self.thread_callback) 
        self.threads.emit('end',self.name)
        
    def start(self, *args):
        thread = threading.Thread(target=self._start, args=args)
        thread.start()
        return thread